package np.com.abhishek.scrambler.ui;

import java.awt.Font;
import java.awt.GridLayout;
import java.awt.Image;
import java.awt.Point;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.awt.event.MouseEvent;
import java.awt.event.MouseListener;
import java.awt.image.CropImageFilter;
import java.awt.image.FilteredImageSource;
import java.awt.image.ImageFilter;
import java.io.File;
import java.util.Random;

import javax.swing.ImageIcon;
import javax.swing.JButton;
import javax.swing.JFrame;
import javax.swing.JInternalFrame;
import javax.swing.JLabel;
import javax.swing.JOptionPane;
import javax.swing.JPanel;
import javax.swing.JTextField;
import javax.swing.SwingConstants;

import np.com.abhishek.scrambler.utils.ImageChooser;
import np.com.abhishek.scrambler.utils.Sound;
import np.com.abhishek.ui.WidgetFactory;

public class Initializer implements ActionListener, MouseListener {
	public static JInternalFrame playWindow = null;

	public static JPanel pnlBoard, pnlBtns;

	public static JButton btn[];

	JButton btnScramble, btnCancel, btnGiveUp;

	static JLabel lblTimer;

	static JTextField statusField;

	Point freePt, currentPt;

	int lastPt;

	static int type, movesMade;

	public static int tiles, size;

	int arrayKeeper[];

	int winCondition[];

	int btnIndex, free, hgap, vgap, defaultGap;

	static int height, width;

	int winCount;

	final int SCRAMBLE = 0;

	final int SOLVE = 1;

	public static int SCARMBLE = 0;

	public static int MOVE = 1;

	public static int ILLEGAL_MOVE = 2;

	public static int HAS_WON = 3;

	public static int GIVE_UP = 4;

	public static int CANCEL = 5;

	public static boolean GAME_HAS_STARTED = false;

	Font btnFont = new Font("Georgia", Font.BOLD, 100 / SizeSelector.size);

	Sound sound;

	ActionListener lsnr;

	public Initializer(int brdSz, int brdTyp) {
		playWindow = new JInternalFrame();
		playWindow.setLayout(null);

		size = brdSz;
		type = brdTyp;
		// System.out.println("type: " + type + "size: " + size);
		tiles = (size * size) - 1;
		movesMade = 0;

		statusField = new JTextField();
		statusField.setText("Number of moves made: ");
		statusField.setEnabled(false);
		statusField.setBounds(5, 480, 430, 25);

		btn = new JButton[tiles];
		hgap = 0;
		vgap = 0;
		defaultGap = 5;
		winCount = 0;

		arrayKeeper = new int[tiles + 1];
		winCondition = new int[tiles];

		sound = new Sound();

		JPanel pnlBtns = new JPanel();

		btnScramble = new JButton("Scramble");
		btnCancel = new JButton("Exit");
		btnGiveUp = new JButton("Give Up");

		pnlBtns.add(btnScramble);
		pnlBtns.add(btnGiveUp);
		pnlBtns.add(btnCancel);

		pnlBtns.setBorder(new javax.swing.border.TitledBorder(""));
		pnlBtns.setBounds(5, 435, 425, 35);
		pnlBtns.setLayout(new GridLayout(1, 3, 30, 10));

		btnScramble.addActionListener(this);
		btnCancel.addActionListener(this);
		btnGiveUp.addActionListener(this);

		pnlBoard = new JPanel();
		pnlBoard.setBounds(5, 5, 425, 425);
		pnlBoard.setLayout(new GridLayout(size, size, hgap, vgap));
		pnlBoard.setBorder(new javax.swing.border.TitledBorder(""));

		playWindow.add(pnlBoard);
		playWindow.add(pnlBtns);
		MainFrame.frame.add(statusField);

		MainFrame.frame.add(playWindow);
	}

	/*
	 * public void keyPressed(KeyEvent k) { System.out.println(k.getKeyChar()); }
	 * public void keyReleased(KeyEvent k) { }
	 * 
	 * public void keyTyped(KeyEvent k) { }
	 */

	public void actionPerformed(ActionEvent evt) {
		if (evt.getSource() == btnCancel) {
			sound.playSound(CANCEL);
			MainFrame.frame.dispose();
		}

		else if (evt.getSource() == btnScramble) {
			MainFrame.mitmFont.setEnabled(false);
			MainFrame.mitmBtnStyle.setEnabled(false);
			scramble();
			/*
			 * lsnr = new TimerTest(); tmr = new Timer(1000, lsnr); tmr.start();
			 * statusField.setText("" + Timers.s);
			 */
		} else if (evt.getSource() == btnGiveUp)
			solve();
		else
			btnIndex = Integer.parseInt(evt.getActionCommand());
	}

	public void mouseClicked(MouseEvent mevt) {
		currentPt = new Point(btn[btnIndex].getLocation());

		if (isNeighbourFree() == true) {
			sound.playSound(MOVE);

			mevt.getComponent().setLocation(freePt);
			freePt = currentPt;
			movesMade++;
			statusField.setText("Number of moves made: " + movesMade);
			int loc = findPosition(currentPt);

			int tempArrVal = arrayKeeper[loc];
			arrayKeeper[loc] = arrayKeeper[free];
			arrayKeeper[free] = tempArrVal;

			free = findPosition(freePt);
			checkWin();
		} else
			sound.playSound(ILLEGAL_MOVE);
	}

	void drawBoard() {
		movesMade = 0;
		int temp = 0;

		for (int i = 1; i <= tiles; i++)
			winCondition[i - 1] = i;

		generateNumber(SOLVE);

		for (int m = 0; m < tiles; m++) {
			temp = arrayKeeper[m] - 1;

			btn[temp] = new JButton();
			btn[temp].setFont(btnFont);
			btn[temp].setBackground(MainFrame.bgCol);
			btn[temp].setForeground(MainFrame.fgCol);
			btn[temp].setHorizontalTextPosition(SwingConstants.CENTER);
			btn[temp].addActionListener(this);
			btn[temp].setActionCommand("" + m);
			btn[temp].addMouseListener(this);
			btn[temp].setVisible(false);

			pnlBoard.add(btn[temp]);
		}

		playWindow.setSize(445, 507);
		playWindow.setLocation(-5, -30);
		playWindow.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
		playWindow.setResizable(false);
		playWindow.setVisible(true);

		GAME_HAS_STARTED = false;
		checkWin();
	}

	public void paintBoard() {
		if (type == SizeSelector.IMAGE) {
			new ImageChooser();

			File f = ImageChooser.file;
			String imagePath = "";
			try {
				imagePath = f.getAbsolutePath();
			} catch (Exception e) {
				JOptionPane
						.showMessageDialog(
								playWindow,
								"Since no file was selected the default \n image file will be loaded.",
								"No Image Selected",
								JOptionPane.INFORMATION_MESSAGE);
				imagePath = "defaultImage.gif";
			}

			Image img1 = WidgetFactory.getInstance().createImage(imagePath);
			Image img = img1.getScaledInstance(size * width, size * height,
					Image.SCALE_FAST);
			ImageIcon imgIc = new ImageIcon(img);

			int imgHeight = imgIc.getIconHeight();
			int imgWidth = imgIc.getIconWidth();

			int row = 0, col = 0;

			try {
				for (int i = 0; i < imgHeight; i += height) {
					col = 0;
					for (int j = 0; j < imgWidth; j += width) {
						ImageFilter crop = new CropImageFilter(j, i, width,
								height);
						Image btnImg = playWindow
								.createImage(new FilteredImageSource(img
										.getSource(), crop));
						ImageIcon imgIcon = new ImageIcon(btnImg);

						int index = row * size + col;
						btn[index].setIcon(imgIcon);
						btn[index].setVisible(true);
						col++;
					}
					row++;
				}
			} catch (Exception e) {
			}
			MainFrame.mitmBgCol.setEnabled(false);
			MainFrame.mitmFgCol.setEnabled(false);
		} else {
			for (int i = 1; i <= tiles; i++) {
				btn[i - 1].setText("" + i);
				if (MainFrame.img1 != null) {
					Image img1 = MainFrame.img1;
					Image img = img1.getScaledInstance(width, height,
							Image.SCALE_FAST);
					ImageIcon imgIcon = new ImageIcon(img);
					btn[i - 1].setIcon(imgIcon);
				}

				btn[i - 1].setVisible(true);
			}
		}

	}

	public void checkWin() // checks the winning condition
	{
		// System.out.println(GAME_HAS_STARTED);
		if (GAME_HAS_STARTED == true) {
			winCount = 0;

			for (int k = 0; k < tiles; k++) {
				if (winCondition[k] == arrayKeeper[k])
					winCount++;
			}
			// System.out.println("" + winCount);

			if (winCount == tiles) {
				GAME_HAS_STARTED = false;

				MainFrame.frame.setTitle("Congratualtions!!! You have won!");
				btnScramble.setEnabled(true);
				sound.playSound(HAS_WON);

				int reply = JOptionPane
						.showConfirmDialog(
								null,
								"   Congratualtions!!! You Win.\n Do you want to start a new game?",
								" MainFrame ", JOptionPane.YES_NO_OPTION);
				if (reply == JOptionPane.YES_OPTION) {
					new SizeSelector(MainFrame.frame);
				}
			} else {
				int winsteps = tiles - winCount;
				MainFrame.frame.setTitle("You are " + winsteps
						+ " steps away from winning!");
			}

		}
	}

	public boolean isRandomSerial() // checks if the generated number series is
	// Serial
	{
		int ctr = 0;
		for (int i = 0; i < tiles; i++)
			if (arrayKeeper[i] == winCondition[i])
				ctr++;

		if (ctr == tiles)
			return true;
		else
			return false;
	}

	public void mouseEntered(MouseEvent mevt) {
	}

	public void mouseExited(MouseEvent mevt) {
	}

	public void mousePressed(MouseEvent mevt) {
	}

	public void mouseReleased(MouseEvent mevt) {
	}

	boolean isNeighbourFree() // checks if the clicked button has a free
	// neighbour
	{
		boolean flag = false;

		if (currentPt.x == freePt.x) {
			if (freePt.y == currentPt.y + vgap + height
					|| freePt.y == currentPt.y - vgap - height)
				flag = true;
		} else if (currentPt.y == freePt.y) {
			if (freePt.x == currentPt.x + hgap + height
					|| freePt.x == currentPt.x - hgap - height)
				flag = true;
		} else
			flag = false;

		// System.out.println("Flag:" + flag);
		return flag;
	}

	void findHtNfreePt() // finds the free point and the heigheight of the
	// button
	{

		height = btn[tiles - 1].getHeight();
		// System.out.println("ht:" + height);
		width = btn[tiles - 1].getWidth();

		lastPt = ((height + hgap) * (size - 1)) + defaultGap;
		freePt = new Point(lastPt, lastPt);

		paintBoard();
	}

	int findPosition(Point p) // returns the position of the clicked button in
	// point p
	{
		int col = (p.x + hgap - defaultGap) / width;
		int row = (p.y + vgap - defaultGap) / height;

		int coord = size * row + col;

		return (coord);
	}

	void generateNumber(int x) {
		if (x == SOLVE) {
			for (int i = 0; i <= tiles; i++)
				arrayKeeper[i] = i + 1;
		} else {
			// JOptionPane.showMessageDialog(null, "random!");
			boolean isinArray = false;
			Random rnum = new Random();
			int i = 0, rtemp, tempcnt;

			while (i != tiles) {
				tempcnt = 0;

				rtemp = 1 + rnum.nextInt(tiles);

				for (int j = 0; j <= i; j++) {
					if (arrayKeeper[j] == rtemp) {
						isinArray = true;
						break;
					} else {
						tempcnt++;
						isinArray = false;
					}
				}

				if (isinArray == false && tempcnt == i + 1) {
					arrayKeeper[i] = rtemp;
					i++;
				}
			}
		}

		arrayKeeper[tiles] = 0;
		free = tiles;
	}

	public void solve() {
		MainFrame.mitmBgCol.setEnabled(true);
		MainFrame.mitmFgCol.setEnabled(true);
		MainFrame.mitmBtnStyle.setEnabled(true);
		MainFrame.mitmFont.setEnabled(true);

		MainFrame.frame.setTitle("Here is the solution for you!");

		btnScramble.setEnabled(true);
		GAME_HAS_STARTED = false;
		Point test;
		int x, y, i, j = 0, index = 0;
		for (i = 0; i < size; i++) {
			y = (height + vgap) * i + defaultGap;
			for (j = 0; j < size; j++) {
				index = (size * i) + j;
				if (index == tiles)
					break;
				else {
					x = (height + hgap) * j + defaultGap;
					test = new Point(x, y);
					btn[index].setLocation(test);
					arrayKeeper[index] = index + 1;
				}
			}
		}
		arrayKeeper[index] = 0;
		free = index;
		freePt = new Point(lastPt, lastPt);
		sound.playSound(GIVE_UP);
	}

	void scramble() {
		movesMade = 0;
		statusField.setText("Number of Moves made: " + movesMade);
		freePt = new Point(lastPt, lastPt);

		GAME_HAS_STARTED = true;
		generateNumber(SCRAMBLE);

		if (isRandomSerial() == true) {
			// JOptionPane.showMessageDialog(null, "RandomSerial generated!");
			generateNumber(SCRAMBLE);
		} else {
			btnScramble.setEnabled(false);
			Point test;
			int x, y, i, j = 0, index = 0;
			for (i = 0; i < size; i++) {
				y = (height + vgap) * i + defaultGap;
				for (j = 0; j <= size; j++) {
					index = (size * i) + j;
					if (index == tiles)
						break;
					else {
						x = (height + hgap) * j + defaultGap;
						test = new Point(x, y);
						int tem = arrayKeeper[index] - 1;
						btn[tem].setLocation(test);
					}
				}

			}
			free = tiles;
		}
		sound.playSound(SCRAMBLE);
	}
}
